
#include "WriteCntCach.h"


WtCntCach::WtCntCach(DWORD dwStartLogSector, DWORD dwSectNumb)
	:m_dwStartLogSect(dwStartLogSector)
	,m_dwNumLogSect(dwSectNumb)
{
}

WtCntCachNormal::WtCntCachNormal(DWORD dwStartLogSector, DWORD dwSectNumb, DWORD dwSectPerBlock)
	:WtCntCach(dwStartLogSector, dwSectNumb)
{
    DWORD i, dwLog2;
    // find log2 of dwSectPerBlock
    for(i=31; i>0; i--)
    {
        dwLog2=(1<<i);
        if(dwLog2&dwSectPerBlock)
        {
            break;
        }
    }

    if(0!=((~dwLog2)&dwSectPerBlock))
    {
        i++;
    }

    if(i<5)
    {
        i=5;
    }

    m_dwCacheSize=(1<<i);
    m_dwCacheSizeMask=m_dwCacheSize-1;
    ASSERT(m_dwCacheSize<=256);

    m_pdwWtCacheAddrS=NULL;
    m_psectExInfoS=NULL;
    
}

BOOL WtCntCachNormal::InitWtCntCache()
{
	WtCntCach::InitWtCntCache();

    m_pdwWtCacheAddrS=new DWORD[m_dwCacheSize];
	m_psectExInfoS=new SectExInfo[m_dwCacheSize];
    if( (NULL==m_pdwWtCacheAddrS)
        || (NULL==m_psectExInfoS) )
    {
        return FALSE;
    }
    
	DWORD i;
	for(i=0; i<m_dwCacheSize; i++)
	{
		m_pdwWtCacheAddrS[i]=INVALID_SECTOR_ADDR;
		m_psectExInfoS[i].dw=0xffffffff;
	}
	
	m_dwLastId=0;

	return TRUE;
}

VOID WtCntCachNormal::DeInitWtCntCache()
{
    if(NULL!=m_pdwWtCacheAddrS)
    {
        delete[] m_pdwWtCacheAddrS;
        m_pdwWtCacheAddrS=NULL;
    }
    if(NULL!=m_psectExInfoS)
    {
        delete[] m_psectExInfoS;
        m_psectExInfoS=NULL;
    }
}

BOOL WtCntCachNormal::GetWtCnt(SECTOR_ADDR sectorAddr, SectExInfo* pSectExInfo)
{
    DWORD i, id;

	for(i=0, id=m_dwLastId; i<m_dwCacheSize; i++, id++)
	{
		id&=m_dwCacheSizeMask;
		
		// find in cache
		if(sectorAddr==m_pdwWtCacheAddrS[id])
		{
			*pSectExInfo=m_psectExInfoS[id];
	
			DWORD idPrev=id-1;
			for(; i>0; i--, id--, idPrev--)
			{
				id&=m_dwCacheSizeMask;
				idPrev&=m_dwCacheSizeMask;
				m_pdwWtCacheAddrS[id]=m_pdwWtCacheAddrS[id-1];
				m_psectExInfoS[id]=m_psectExInfoS[id-1];
			}
	
			m_pdwWtCacheAddrS[m_dwLastId]=sectorAddr;
			m_psectExInfoS[m_dwLastId]=*pSectExInfo;
	
			return TRUE;
		}
	}

	// can't get write count in cache
	return FALSE;
}

BOOL WtCntCachNormal::CacheWtCnt(SECTOR_ADDR sectorAddr, SectExInfo* pSectExInfo)
{
    DWORD i, id;
	
	for(i=0, id=m_dwLastId; i<m_dwCacheSize; i++, id++)
	{
		id&=m_dwCacheSizeMask;
		
		// find in cache, and don't adjust the cache order
		if(sectorAddr==m_pdwWtCacheAddrS[id])
		{
			m_psectExInfoS[id]=*pSectExInfo;
			return TRUE;
		}
	}

	// not in cache
	m_dwLastId--;
	m_dwLastId&=m_dwCacheSizeMask;

	m_pdwWtCacheAddrS[m_dwLastId]=sectorAddr;
	m_psectExInfoS[m_dwLastId]=*pSectExInfo;

	return TRUE;

}

BOOL WtCntCachNormal::UncacheWtCnt(SECTOR_ADDR sectorAddr)
{
    DWORD i, id;
	
	for(i=0, id=m_dwLastId; i<m_dwCacheSize; i++, id++)
	{
		id&=m_dwCacheSizeMask;
		
		// find in cache, and don't adjust the cache order
		if(sectorAddr==m_pdwWtCacheAddrS[id])
		{
			m_pdwWtCacheAddrS[i]=INVALID_SECTOR_ADDR;
			m_psectExInfoS[i].dw=0xffffffff;

			if(i==m_dwLastId)
			{
				m_dwLastId++;
				m_dwLastId&=m_dwCacheSizeMask;
			}
			return TRUE;
		}
	}

	// not in cache
	return TRUE;

}


WtCntCachStartUp::WtCntCachStartUp(DWORD dwStartLogSector, DWORD dwSectNumb)
	:WtCntCach(dwStartLogSector, dwSectNumb)
    ,m_dwNumSectorsPerSecTable(0)
{
	m_dwNumSectorsPerSecTable = (m_dwNumLogSect + MASTER_CHACHE_TABLE_SIZE - 1) / MASTER_CHACHE_TABLE_SIZE;
}

WtCntCachStartUp::~WtCntCachStartUp()
{
	DeInitWtCntCache();
}

BOOL WtCntCachStartUp::InitWtCntCache()
{
	WtCntCach::InitWtCntCache();

    for(int i=0; i<MASTER_CHACHE_TABLE_SIZE; i++)
    {
        m_pSectExInfo[i] = NULL;
    }

	return TRUE;
}

VOID WtCntCachStartUp::DeInitWtCntCache()
{
	for(int i=0; i<MASTER_CHACHE_TABLE_SIZE; i++)
	{
		if(m_pSectExInfo[i] != NULL)
		{
			LocalFree(m_pSectExInfo[i]);
			m_pSectExInfo[i]=NULL;
		}
	}
	
	WtCntCach::DeInitWtCntCache();
}

BOOL WtCntCachStartUp::GetWtCnt(SECTOR_ADDR sectorAddr, SectExInfo* pSectExInfo)
{

	if (sectorAddr < m_dwStartLogSect || sectorAddr >= (m_dwStartLogSect + m_dwNumLogSect)) 
	{
		DEBUGMSG( ZONE_WARNING, (TEXT("!!! GetWtCnt sect:0x%x out of range !!!\r\n"), sectorAddr));
		return FALSE;
	}

	
	sectorAddr -= m_dwStartLogSect;

	DWORD dwSecondaryTableID=sectorAddr/m_dwNumSectorsPerSecTable;
	ASSERT(dwSecondaryTableID < MASTER_CHACHE_TABLE_SIZE);

	// not cached, for startup return INIT_WRITE_CNT
	if(m_pSectExInfo[dwSecondaryTableID] == NULL)	
	{
		pSectExInfo->dw = 0xffffffff;
		return FALSE;
	}

	DWORD dwOffset=sectorAddr%m_dwNumSectorsPerSecTable;
	*pSectExInfo=m_pSectExInfo[dwSecondaryTableID][dwOffset];

	return TRUE;
}

BOOL WtCntCachStartUp::CacheWtCnt(SECTOR_ADDR sectorAddr, SectExInfo* pSectExInfo)
{
	if (sectorAddr < m_dwStartLogSect || sectorAddr >= (m_dwStartLogSect + m_dwNumLogSect)) 
	{
		DEBUGMSG( ZONE_WARNING, (TEXT("!!! GetWtCnt sect:0x%x out of range !!!\r\n"), sectorAddr));
		return FALSE;
	}

	
	sectorAddr -= m_dwStartLogSect;

	DWORD dwSecondaryTableID=sectorAddr/m_dwNumSectorsPerSecTable;
	ASSERT(dwSecondaryTableID < MASTER_CHACHE_TABLE_SIZE);

	if(m_pSectExInfo[dwSecondaryTableID] == NULL)
	{
		m_pSectExInfo[dwSecondaryTableID] = (SectExInfo*)LocalAlloc(LMEM_FIXED, m_dwNumSectorsPerSecTable*sizeof(SectExInfo));
		if(NULL==m_pSectExInfo[dwSecondaryTableID])
		{
			DEBUGMSG( ZONE_WARNING, (TEXT("!!! Unable to allocate secondary table for logical sector %d\r\n!!!"), sectorAddr));
			return FALSE;
		}
		memset(m_pSectExInfo[dwSecondaryTableID], 0xff, m_dwNumSectorsPerSecTable*sizeof(SectExInfo));
	}
	
	DWORD dwOffset=sectorAddr%m_dwNumSectorsPerSecTable;
	m_pSectExInfo[dwSecondaryTableID][dwOffset]=*pSectExInfo;

	return TRUE;
}

